/**
	@file
	Contains physical drives IO functions.
	IO functions allow binary access to physical drives using LBA addressing.
	Read/Write functions returns diskResult struct containing errorCode (not only) (error codes
	are defined below).
	For IO functions operating with partitions see \ref partitioning.h, \ref partitioning.c.

	@warning \ref diskRead and \ref diskWrite function should be changed according to the storage type used.
	@note Now those functions are operating with image file. (For debugging)
	@author Konstantin Kastanov
*/
#include "headers/diskIO.h"
#include "../tools/headers/common.h"
#include "../api/headers/errors.h"
#include "../api/headers/string.h"
#include "../api/headers/io.h"

typedef struct
{
	u32int startAddr;
	u32int endAddr;
} Drive;

static Drive driveArray[MAX_DRIVE_NUMBER];

/**
	Reads specified sectors from a specified drive to a buffer. Mounting the drive
	does not affect this function.
	@par Errors:
				\li \ref ERR_DEVICE_NOT_FOUND if drive > \ref MAX_DRIVE_NUMBER or drive is not accessible
				\li \ref ERR_BAD_ADDRESS if specified \c sectorNumber or \c sectorNumber +
					\c sectorCount does not exist on the drive.
	@return Number of sectors actually read.
	@note Function provides raw binary read. No partition management is implied.
*/
u32int diskRead(
				u8int drive,          /**<[in] Physical drive number */
				u8int* buffer,        /**<[out] Pointer to the read data buffer */
				u32int sectorNumber,  /**<[in] Start sector number */
				u32int sectorCount     /**<[in] Number of sectors to read */
			)
{
	setLastError(NO_ERROR);
#ifdef DEBUG
	printf("Reading from disk.\n");
#endif
	u32int sectorsRead = 0;
	u32int beginReadByte;

	sectorsRead = 0;
	
	if(drive > MAX_DRIVE_NUMBER)
	{
		setLastError(ERR_DEVICE_NOT_FOUND);
		return 0;
	}

	if(driveArray[drive].startAddr == 0)
	{
		setLastError(ERR_DEVICE_NOT_FOUND);
		return 0;
	}

	beginReadByte = sectorNumber * SECTOR_SIZE;
	
	if((driveArray[drive].startAddr + beginReadByte + sectorCount * SECTOR_SIZE) > driveArray[drive].endAddr) //Check if size is valid
	{
		printf("Out of disk bounds. start 0x%H;   end 0x%H;  count 0x%H;\n", driveArray[drive].startAddr, driveArray[drive].endAddr, sectorCount);
		printf("left op: 0x%H;   right op: 0x%H\n", driveArray[drive].startAddr + beginReadByte + sectorCount * SECTOR_SIZE,
			   driveArray[drive].endAddr);
		printf("BeginReadByte: 0x%H;  SECTOR_SIZE: 0x%H; sectorNumber: 0x%H; sectorCount: 0x%H\n",
			beginReadByte, SECTOR_SIZE, sectorNumber, sectorCount);
		
		setLastError(ERR_BAD_ADDRESS);
		return 0;
	}
	
	memcpy(buffer,(void*)(driveArray[drive].startAddr + beginReadByte), sectorCount * SECTOR_SIZE);
	
	

	
	return sectorCount;
}

/**
	Writes data from buffer to the specified sectors on the specified drive. Mounting the drive
	does not affect this function.
	@return Number of actually written sectors.
	@note Function provides raw binary write. No partition management is implied.
	@warning Not implemented yet.
*/
u32int diskWrite(
				  u8int drive,          /**< Physical drive number */
				  const u8int* buffer,  /**< Pointer to the write data */
				  u32int sectorNumber,  /**< Sector number to write */
				  u32int sectorCount     /**< Number of sectors to write */
				)
{

	u8int sectorsWritten = 0;
	setLastError(ERR_DEVICE_NOT_FOUND);
	return sectorsWritten;
}

/**
	Adds memory chunk as a drive.
	@warning Temp function. Only for debugging
*/
u8int addDisk(u32int startAddr, u32int endAddr, u8int driveNumber) //Assign file to a hardware disk. Returns error code
{
	if(driveNumber > MAX_DRIVE_NUMBER)
	{
		setLastError(ERR_DEVICE_NOT_FOUND);
		return ERR_DEVICE_NOT_FOUND;
	}
	
	if((s32int)(endAddr - startAddr) < 1024)
	{
		setLastError(ERR_BAD_ADDRESS);
		return ERR_BAD_ADDRESS;
	}
	driveArray[driveNumber].startAddr = startAddr;
	driveArray[driveNumber].endAddr = endAddr;

	setLastError(NO_ERROR);
	return NO_ERROR;
}

